মিউটেক্স এবং সিঙ্ক্রোনাইজেশন

Computer Programming - সি++ প্রোগ্রামিং (C++ Programming) মাল্টিথ্রেডিং |
329
329

মিউটেক্স (Mutex) হলো C++ এর একটি সিঙ্ক্রোনাইজেশন প্রক্রিয়া, যা একাধিক থ্রেডকে সমন্বিতভাবে ডেটা ব্যবহারের সুযোগ দেয়, কিন্তু এক থ্রেড অন্য থ্রেডের কাজ শেষ না হওয়া পর্যন্ত সেই ডেটা অ্যাক্সেস করতে পারে না। মিউটেক্স ব্যবহার করে একাধিক থ্রেডের মধ্যে ডেটা শেয়ার করার সময় ডেটার সামঞ্জস্যতা (consistency) বজায় রাখা যায় এবং ডেটা রেস সমস্যা প্রতিরোধ করা যায়।

সিঙ্ক্রোনাইজেশন এবং এর প্রয়োজনীয়তা

সিঙ্ক্রোনাইজেশন একটি প্রক্রিয়া, যা নিশ্চিত করে যে একাধিক থ্রেড একসঙ্গে একই ডেটা অ্যাক্সেস বা মডিফাই করতে পারবে না। যদি সিঙ্ক্রোনাইজেশন না করা হয়, তবে ডেটা রেস নামক সমস্যা হতে পারে, যেখানে একাধিক থ্রেড একসঙ্গে একই ডেটা মডিফাই করতে গেলে ভুল বা অনির্দেশ্য আউটপুট আসতে পারে।

সিঙ্ক্রোনাইজেশন ব্যবহারের প্রয়োজনীয়তা:

  1. ডেটা রেস প্রতিরোধ: সিঙ্ক্রোনাইজেশন ডেটা রেস প্রতিরোধ করে, যেখানে একাধিক থ্রেড একসঙ্গে ডেটা মডিফাই করার চেষ্টা করে।
  2. ডেটার সঠিকতা বজায় রাখা: এটি ডেটার সঠিকতা এবং সামঞ্জস্য বজায় রাখে, যাতে প্রোগ্রাম নির্ভুলভাবে চলে।
  3. ডেডলক প্রতিরোধ: সঠিক সিঙ্ক্রোনাইজেশন প্রক্রিয়া ব্যবহার করে ডেডলক প্রতিরোধ করা সম্ভব।

C++ এ মিউটেক্স ব্যবহারের প্রক্রিয়া

C++ এ mutex লাইব্রেরি থেকে মিউটেক্স ব্যবহৃত হয়। এটি সাধারণত তিনটি মেথড দ্বারা কাজ করে:

  • lock(): মিউটেক্স লক করে, অর্থাৎ কোনো থ্রেড এটি লক করে রাখলে অন্য থ্রেড এটি অ্যাক্সেস করতে পারবে না।
  • unlock(): মিউটেক্স আনলক করে, অর্থাৎ অন্য থ্রেড এই মিউটেক্স অ্যাক্সেস করতে পারবে।
  • try_lock(): মিউটেক্স লক করতে চেষ্টা করে এবং সফল হলে true রিটার্ন করে, ব্যর্থ হলে false রিটার্ন করে।

উদাহরণ: মিউটেক্স ব্যবহার করে সিঙ্ক্রোনাইজেশন

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx; // মিউটেক্স তৈরি করা

void printMessage(const string& msg) {
    mtx.lock(); // মিউটেক্স লক করা
    cout << msg << endl;
    mtx.unlock(); // মিউটেক্স আনলক করা
}

int main() {
    thread t1(printMessage, "Hello from thread 1");
    thread t2(printMessage, "Hello from thread 2");

    t1.join();
    t2.join();

    return 0;
}

বর্ণনা:

  • এখানে mtx.lock() এবং mtx.unlock() ব্যবহার করে মিউটেক্স লক এবং আনলক করা হয়েছে, যাতে cout স্টেটমেন্ট একসঙ্গে একাধিক থ্রেড দ্বারা অ্যাক্সেস না হয়।
  • এক থ্রেডের কাজ সম্পূর্ণ হলে অন্য থ্রেড লকটি পায় এবং কাজ শুরু করে।

লকার (Lock Guard) ব্যবহার করে মিউটেক্স

লকার ব্যবহার করে মিউটেক্সের লক এবং আনলক করা আরও সহজ করা যায়। lock_guard একটি সিঙ্ক্রোনাইজেশন ক্লাস, যা মিউটেক্স লক করে এবং যখন স্কোপের বাইরে চলে যায়, তখন স্বয়ংক্রিয়ভাবে আনলক করে।

উদাহরণ: lock_guard ব্যবহার

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx;

void printMessage(const string& msg) {
    lock_guard<mutex> lock(mtx); // lock_guard ব্যবহার করে মিউটেক্স লক
    cout << msg << endl;
}

int main() {
    thread t1(printMessage, "Hello from thread 1");
    thread t2(printMessage, "Hello from thread 2");

    t1.join();
    t2.join();

    return 0;
}

বর্ণনা:

  • এখানে lock_guard ব্যবহার করে মিউটেক্স লক করা হয়েছে, এবং কাজ শেষে এটি স্বয়ংক্রিয়ভাবে আনলক হয়।
  • ফলে প্রোগ্রামারকে ম্যানুয়ালি unlock() কল করার দরকার নেই, যা কোডকে আরও সুরক্ষিত এবং পরিষ্কার করে তোলে।

ডেডলক এবং তার প্রতিরোধ

ডেডলক হলো এমন একটি অবস্থা যেখানে দুটি বা ততোধিক থ্রেড একে অপরের উপর নির্ভরশীল হয়ে অপেক্ষা করে, ফলে তারা কোন কাজই করতে পারে না। সাধারণত মিউটেক্স ব্যবহারের সময় ডেডলক সমস্যা দেখা দিতে পারে।

ডেডলক প্রতিরোধের জন্য কিছু পদ্ধতি:

  1. লক করার ক্রম ঠিক রাখা: একাধিক মিউটেক্স ব্যবহারের সময় লক করার ক্রম ঠিক রাখা।
  2. try_lock() ব্যবহার: try_lock() ব্যবহার করে ডেডলক প্রতিরোধ করা যায়, কারণ এটি ব্যর্থ হলে false রিটার্ন করে, ফলে থ্রেডটি অবিরত অপেক্ষা করে না।
  3. লকার (lock_guard) ব্যবহার: lock_guard বা unique_lock ব্যবহার করে লক করার প্রক্রিয়া সহজ করা যায় এবং স্কোপের বাইরে যাওয়ার সময় এটি স্বয়ংক্রিয়ভাবে আনলক হয়।

উদাহরণ: ডেডলক প্রতিরোধের জন্য try_lock() ব্যবহার

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx1, mtx2;

void thread1() {
    if (mtx1.try_lock()) { 
        this_thread::sleep_for(chrono::milliseconds(100)); // সামান্য বিরতি
        if (mtx2.try_lock()) {
            cout << "Thread 1 is running." << endl;
            mtx2.unlock();
        }
        mtx1.unlock();
    }
}

void thread2() {
    if (mtx2.try_lock()) { 
        this_thread::sleep_for(chrono::milliseconds(100)); // সামান্য বিরতি
        if (mtx1.try_lock()) {
            cout << "Thread 2 is running." << endl;
            mtx1.unlock();
        }
        mtx2.unlock();
    }
}

int main() {
    thread t1(thread1);
    thread t2(thread2);

    t1.join();
    t2.join();

    return 0;
}

বর্ণনা:

  • এখানে try_lock() ব্যবহার করে থ্রেডে ডেডলক প্রতিরোধ করা হয়েছে।
  • এক থ্রেড যদি try_lock() এর মাধ্যমে লক করতে ব্যর্থ হয়, তবে সেটি অবিরত অপেক্ষা না করে ফিরে আসে এবং পরবর্তী কাজ করতে পারে।

সিঙ্ক্রোনাইজেশন ব্যবহারের সুবিধা

  1. ডেটার সঠিকতা বজায় রাখা: মিউটেক্স ব্যবহার করে ডেটার সমন্বিত অ্যাক্সেস নিশ্চিত করা যায়।
  2. ডেটা রেস প্রতিরোধ: মিউটেক্স একাধিক থ্রেডের মধ্যে ডেটা রেস সমস্যা প্রতিরোধ করে।
  3. ডেডলক সমস্যা সমাধান: সঠিক লকিং কৌশল এবং lock_guardtry_lock() ব্যবহার করে ডেডলক সমস্যার সমাধান করা যায়।

সারসংক্ষেপ

  • মিউটেক্স C++ এ থ্রেড সিঙ্ক্রোনাইজেশনের জন্য ব্যবহৃত একটি প্রক্রিয়া, যা ডেটা রেস এবং ডেডলক সমস্যা প্রতিরোধ করে।
  • lock(), unlock() এবং try_lock() ব্যবহার করে মিউটেক্স লক ও আনলক করা হয়।
  • lock_guard এবং unique_lock সিঙ্ক্রোনাইজেশন আরও সহজ করে তোলে এবং স্কোপের বাইরে যাওয়ার সময় মিউটেক্স স্বয়ংক্রিয়ভাবে আনলক করে।

মিউটেক্স এবং সিঙ্ক্রোনাইজেশন ব্যবহার করে প্রোগ্রামে ডেটা শেয়ারিং আরও নিরাপদ এবং নির্ভরযোগ্য করা যায়, যা বড় মাল্টিথ্রেডেড প্রোগ্রাম তৈরিতে অত্যন্ত গুরুত্বপূর্ণ।

common.content_added_by
টপ রেটেড অ্যাপ

স্যাট অ্যাকাডেমী অ্যাপ

আমাদের অল-ইন-ওয়ান মোবাইল অ্যাপের মাধ্যমে সীমাহীন শেখার সুযোগ উপভোগ করুন।

ভিডিও
লাইভ ক্লাস
এক্সাম
ডাউনলোড করুন
Promotion